/**
 * 
 */
package com.ubo.transform.dot;

import java.util.HashMap;
import java.util.Map;

import com.ubo.graphviz.model.graph.EGraphType;
import com.ubo.graphviz.model.graph.Graph;
import com.ubo.graphviz.model.graph.statement.Attribute;
import com.ubo.graphviz.model.graph.statement.AttributeStmt;
import com.ubo.graphviz.model.graph.statement.EdgeStatementNode;
import com.ubo.graphviz.model.graph.statement.EdgeStmtSubgraph;
import com.ubo.graphviz.model.graph.statement.IStatement;
import com.ubo.graphviz.model.graph.statement.Subgraph;
import com.ubo.graphviz.model.graph.statement.node.NodeStmt;
import com.ubo.graphviz.model.graph.statement.node.classNode.ClassStmt;
import com.ubo.transform.ITransformConstants;

/**
 * @author saludegu
 * 
 */
public class DotGenerator extends ADotVisitor<StringBuffer> {

	/**
	 * Map contenant les statements en fonction de leur id.
	 */
	protected Map<Integer, NodeStmt> mMapStatements;

	protected EGraphType mCurrGraphType = EGraphType.DIRECTED;

	/**
	 * 
	 * Constructor
	 * 
	 */
	public DotGenerator() {
		super();
		mMapStatements = new HashMap<Integer, NodeStmt>();
	}

	/**
	 * Verifie la valeur du type courant de graph.
	 * 
	 * @param graphType
	 */
	protected void checkCurrGraphType(EGraphType graphType) {
		if (!graphType.equals(mCurrGraphType)) {
			mCurrGraphType = graphType;
		}
	}

	/**
	 * @see com.ubo.transform.dot.IDotVisitor#generate(com.ubo.graphviz.model.graph.Graph)
	 */
	@Override
	public void generate(Graph graph) {
		checkCurrGraphType(graph.getType());
		StringBuffer buffer = new StringBuffer();
		graph.getType().generate(this);
		buffer.append(getValue() + " " + graph.getName() + " { \n");
		for (IStatement stmt : graph.getStatements()) {
			stmt.generate(this);
			if (!isEmpty())
				buffer.append(getValue().toString());
		}
		buffer.append("}");
		addToStack(buffer);
	}

	/**
	 * @see com.ubo.transform.dot.IDotVisitor#generate(com.ubo.graphviz.model.graph.statement.node.NodeStmt)
	 */
	@Override
	public void generate(NodeStmt stmt) {
		StringBuffer buffer = new StringBuffer();
		buffer.append(stmt.getName() + "[type=" + stmt.getType() + ",");
		if (stmt.getAttributes() != null) {
			buffer.append("shape=record" + ",label=\"");
			String curr = ITransformConstants.ATTRIBUTE_TYPE_VALUE_ATTRIBUTE;
			String currLineTokenStart = "#";
			buffer.append("{");
			for (Attribute attr : stmt.getAttributes().getAttributes()) {
				generate(attr);
				String currString = getFromStack().toString();
				String[] tabStr = currString.split(":");
				if (!curr.equals(tabStr[0])) {
					curr = tabStr[0];
					buffer.append("}{");
				}
				buffer.append(currLineTokenStart + tabStr[1]);
			}
			buffer.append("}\"");
		}
		buffer.append("];\n");
		addToStack(buffer);
		mMapStatements.put(stmt.getIdNode(), stmt);
	}

	/**
	 * @see com.ubo.transform.dot.IDotVisitor#generate(com.ubo.graphviz.model.graph.statement.node.classNode.ClassStmt)
	 */
	@Override
	public void generate(ClassStmt stmt) {
		StringBuffer buffer = new StringBuffer();
		if (stmt.getAttributes() != null) {
			buffer.append(stmt.getName() + "[type=" + stmt.getType()
					+ "shape=record, 	label=\"" + stmt.getName() + "\"");
			for (Attribute attr : stmt.getAttributes().getAttributes()) {
				generate(attr);
				buffer.append(getFromStack() + "\n");
			}
			buffer.append("}\n");
		}
		addToStack(buffer);
		mMapStatements.put(stmt.getIdNode(), stmt);
	}

	/**
	 * @see com.ubo.transform.dot.IDotVisitor#generate(com.ubo.graphviz.model.graph.statement.EdgeStatementNode)
	 */
	@Override
	public void generate(EdgeStatementNode stmt) {
		StringBuffer buffer = new StringBuffer();
		String token = "--";
		if (mCurrGraphType.equals(EGraphType.DIRECTED))
			token = "->";
		buffer.append(mMapStatements.get(stmt.getIdFrom()).getName() + token
				+ mMapStatements.get(stmt.getIdTo()).getName());
		for (Attribute attr : stmt.getAttributes().getAttributes()) {
			buffer.append("\"" + attr.getValue() + "\"");
		}
		buffer.append(";\n");
		addToStack(buffer);
	}

	/**
	 * @see com.ubo.transform.dot.IDotVisitor#generate(com.ubo.graphviz.model.graph.statement.Attribute)
	 */
	@Override
	public void generate(Attribute attr) {
		StringBuffer buffer = new StringBuffer();
		buffer.append(attr.getName() + ":" + attr.getValue());
		addToStack(buffer);
	}

	/**
	 * @see com.ubo.transform.dot.IDotVisitor#generate(com.ubo.graphviz.model.graph.statement.AttributeStmt)
	 */
	@Override
	public void generate(AttributeStmt stmt) {
		StringBuffer buffer = new StringBuffer();
		for (Attribute attr : stmt.getAttributeList().getAttributes()) {
			generate(attr);
			buffer.append(getFromStack() + "\n");
		}
		addToStack(buffer);
	}

	/**
	 * @see com.ubo.transform.dot.IDotVisitor#generate(com.ubo.graphviz.model.graph.statement.EdgeStmtSubgraph)
	 */
	@Override
	public void generate(EdgeStmtSubgraph stmt) {
		StringBuffer buffer = new StringBuffer();
		addToStack(buffer);
	}

	/**
	 * @see com.ubo.transform.dot.IDotVisitor#generate(com.ubo.graphviz.model.graph.statement.Subgraph)
	 */
	@Override
	public void generate(Subgraph stmt) {
		StringBuffer buffer = new StringBuffer();
		buffer.append(stmt.getName());
		addToStack(buffer);
	}

	/**
	 * @param eGraphType
	 */
	public void generate(EGraphType eGraphType) {
		StringBuffer buffer = new StringBuffer();
		if (eGraphType.equals(EGraphType.DIRECTED))
			buffer.append("digraph");
		else if (eGraphType.equals(EGraphType.UNDIRECTED))
			buffer.append("graph");
		addToStack(buffer);
	}

}